#pragma once

#include "Protocol.hpp"
#include <iostream>

class BaseService
{
public:
    BaseService() = default;    
    virtual ~BaseService() = default;

    virtual std::shared_ptr<Protocol::Response> Do(std::shared_ptr<Protocol::Request>) = 0;
};

namespace CalculateNS
{
    enum class CalError
    {
        InvalidOpError = 1,
        DivByZeroError,
        ModByZeroError
    };

    class Calculate: public BaseService
    {
    public:
        Calculate() = default;

        std::shared_ptr<Protocol::Response> Do(std::shared_ptr<Protocol::Request> req) override
        {
            auto cal_req = std::dynamic_pointer_cast<Protocol::Cal_Request>(req);
            auto resp = _factory.CreateCalResponse(0);
            auto cal_resp = std::dynamic_pointer_cast<Protocol::Cal_Response>(resp);

            switch (cal_req->GetOp())
            {
            case '+':
                cal_resp->SetResult(cal_req->GetX() + cal_req->GetY());
                break;
            case '-':
                cal_resp->SetResult(cal_req->GetX() - cal_req->GetY());
                break;
            case '*':
                cal_resp->SetResult(cal_req->GetX() * cal_req->GetY());
                break;
            case '/':
                if (cal_req->GetY() == 0)
                {
                    cal_resp->SetErrorCode(static_cast<int>(CalError::DivByZeroError));
                    break;
                }
                cal_resp->SetResult(cal_req->GetX() / cal_req->GetY());
                break;
            case '%':
                if (cal_req->GetY() == 0)
                {
                    cal_resp->SetErrorCode(static_cast<int>(CalError::ModByZeroError));
                    break;
                }
                cal_resp->SetResult(cal_req->GetX() % cal_req->GetY());
                break;
            default:
                std::cout << "Invalid operator" << std::endl;
                cal_resp->SetErrorCode(static_cast<int>(CalError::InvalidOpError));
                break;
            }
            return resp;
        }

    private:
        Protocol::Cal_Factory _factory;
    };
} // namespace CalculateNS
